<template>
  <div class="domApiPrc">
     <!-- <canvas>标记提供webgl绘制区域 -->
    <canvas ref="myGLCanvas" :width="rect?.width" :height="rect?.height"/>
  </div>
</template>

<script lang="ts">
import { Vue, Options } from 'vue-property-decorator';
// import  from 'webgl-debug'
@Options({ components: {} })
export default class DomApiPrc extends Vue {
  public rect: DOMRect|null = null;
  public gl!: WebGLRenderingContext;
  public shaderProgram: WebGLProgram|null=null;
  public vertexBuffer: WebGLBuffer|null = null;
  public vertexPositionAttribute=0;
  public vertexColorAttribute=0;
  public buffer: ArrayBuffer|null=null;
  public positionView: Float32Array|null = null;
  public colorView: Uint8Array|null = null;


  public draw() {
    this.gl.viewport(0, 0, this.rect!.width, this.rect!.height);// 定义一个视口
    this.gl.clear(this.gl.COLOR_BUFFER_BIT);// 通过参数this.gl.COLOR_BUFFER_BIT把颜色缓冲清除为事先用 this.gl.clearColor()定义的颜色
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
    this.gl.vertexAttribPointer(this.vertexPositionAttribute, 3, this.gl.FLOAT, false, 16, 0);
    this.gl.vertexAttribPointer(this.vertexColorAttribute, 4, this.gl.UNSIGNED_BYTE, true, 16, 12);
    // gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
    this.gl.drawArrays(this.gl.TRIANGLES, 0, 3); // 用于从向量数组中绘制图元 gl.drawArrays(mode, first, count);
    requestAnimationFrame(() => {
      this.draw();
    });
    // requestAnimationFrame(this.startUp.bind(this));
    // 错误写法
    // requestAnimationFrame(this.startUp);
  }
  // 3.建立缓冲，用来保存顶点数据
  public setupBuffers() {
    this.vertexBuffer = this.gl.createBuffer(); // 创建并初始化一个用于储存顶点数据或着色数据的WebGLBuffer对象
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);// 把新建的WebGLBuffer对象绑定为当前的数组缓冲对象
    const triangleVertices = [
      0.0, 0.5, 0.0, 255, 0, 0, 255,
      -0.5, -0.5, 0.0, 0, 250, 0, 255,
      0.5, -0.5, 0.0, 0, 0, 255, 255,
    ];
    this.buffer = new ArrayBuffer(48);
    this.positionView = new Float32Array(this.buffer);
    this.colorView = new Uint8Array(this.buffer);
    let k = 0;
    for (let i = 0; i < 3; i++) {
      this.positionView[i * 4] = triangleVertices[k];
      this.positionView[i * 4 + 1] = triangleVertices[k + 1];
      this.positionView[i * 4 + 2] = triangleVertices[k + 2];
      this.colorView[i * 16 + 12] = triangleVertices[k + 3];
      this.colorView[i * 16 + 13] = triangleVertices[k + 4];
      this.colorView[i * 16 + 14] = triangleVertices[k + 5];
      this.colorView[i * 16 + 15] = triangleVertices[k + 6];
      k += 7;
    }
    // this.buffer = new ArrayBuffer(48);
    // this.positionView = new Float32Array(this.buffer);
    // this.colorView = new Uint8Array(this.buffer);
    // let positionOffsetFloats = 0; // 偏移量
    // let colorOffsetBytes = 12;
    // let k = 0;
    // for (let i = 0; i < 3; i++) {
    //   this.positionView[positionOffsetFloats] = triangleVertices[k];
    //   this.positionView[positionOffsetFloats + 1] = triangleVertices[k + 1];
    //   this.positionView[positionOffsetFloats + 2] = triangleVertices[k + 2];
    //   this.colorView[colorOffsetBytes] = triangleVertices[k + 3];
    //   this.colorView[colorOffsetBytes + 1] = triangleVertices[k + 4];
    //   this.colorView[colorOffsetBytes + 2] = triangleVertices[k + 5];
    //   this.colorView[colorOffsetBytes + 3] = triangleVertices[k + 6];
    //   positionOffsetFloats += 4;
    //   colorOffsetBytes += 16;
    //   k += 7;
    // }
    // 把顶点数据写入当前绑定的WebGLBuffer对象中
    // 告诉WebGL哪些数据保存在this.gl.createBuffer()创建的缓冲区中
    this.gl.bufferData(this.gl.ARRAY_BUFFER, this.buffer, this.gl.STATIC_DRAW);
    this.gl.vertexAttribPointer(this.vertexPositionAttribute, 3, this.gl.FLOAT, false, 16, 0); // 告诉WebGL从当前绑定的缓冲区读取顶点数据
    this.gl.vertexAttribPointer(this.vertexColorAttribute, 4, this.gl.UNSIGNED_BYTE, true, 16, 12);
    this.gl.enableVertexAttribArray(this.vertexPositionAttribute); // 打开属性数组列表中指定索引处的通用顶点属性数组 不用重复激活 一次就可以
    this.gl.enableVertexAttribArray(this.vertexColorAttribute); // 打开属性数组列表中指定索引处的通用顶点属性数组 不用重复激活 一次就可以
  }
  public setupShaders() {
    // 1.创建着色器
    // 编写着色器源代码
    const vertexShaderSource = `precision mediump float;
                                attribute vec3 aVertexPosition;
                                attribute vec4 aVertexColor;
                                varying vec4 vColor;
                                void main(){
                                  vColor = aVertexColor;
                                  gl_Position = vec4(aVertexPosition,1.0);
                                }`;
    // gl_Position放置顶点坐标信息
    const fragmentShaderSource = `precision mediump float;
                                  varying vec4 vColor;
                                  void main(){
                                    gl_FragColor = vColor;
                                  }`;
    // gl_FragColor设置当前片点的颜色

    // 根据源代码创建着色器
    const vertexShader = this.loadShader(this.gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = this.loadShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
    // 2.创建程序对象和链接着色器
    // createProgram()创建和初始化一个 WebGLProgram 对象。一个 WebGLProgram 对象由两个编译过后的 WebGLShader 组成 - 顶点着色器和片段着色器
    this.shaderProgram = this.gl.createProgram();
    // attachShader()负责往 WebGLProgram 添加一个片段或者顶点着色器。
    this.gl.attachShader(this.shaderProgram!, vertexShader!);
    this.gl.attachShader(this.shaderProgram!, fragmentShader!);
    // inkProgram()方法链接给定的WebGLProgram，从而完成为程序的片元和顶点着色器准备GPU代码的过程。
    this.gl.linkProgram(this.shaderProgram!);
    if (!this.gl.getProgramParameter(this.shaderProgram!, this.gl.LINK_STATUS)) {
      alert('Failed to setup shaders');
    }
    this.gl.useProgram(this.shaderProgram!);// 告诉webgl引擎可以用这个程序对象绘制图像
    // getAttribLocation() 方法返回了给定WebGLProgram对象中某属性的下标指向位置。 把顶点着色器使用的属性绑定到通用属性索引上
    this.vertexPositionAttribute = this.gl.getAttribLocation(this.shaderProgram!, 'aVertexPosition');
    this.vertexColorAttribute = this.gl.getAttribLocation(this.shaderProgram!, 'aVertexColor');
    // this.gl.enableVertexAttribArray(this.vertexPositionAttribute); // 打开属性数组列表中指定索引处的通用顶点属性数组 不用重复激活 一次就可以
    // this.gl.enableVertexAttribArray(this.vertexColorAttribute); // 打开属性数组列表中指定索引处的通用顶点属性数组 不用重复激活 一次就可以
  }
  // 1.创建一个可以载入到GPU并且能够绘制几何图形的WebGL着色器
  public loadShader(type: number, shaderSource: any) {  // type 类型应该是什么
    const shader = this.gl.createShader(type);// 创建一个WebGLShader着色器对象
    this.gl.shaderSource(shader!, shaderSource);// 挂载GLSL源代码
    this.gl.compileShader(shader!);// 完成着色器的编译

    // 检查编译的状态，如果出现错误，发出警告消息，并删除着色器对象
    if (!this.gl.getShaderParameter(shader!, this.gl.COMPILE_STATUS)) {
      alert(`Error Compiling shader${this.gl.getShaderInfoLog(shader!)}`);
      this.gl.deleteShader(shader);
      return null;
    }

    return shader;
  }
  public mounted() {
    // Element.getBoundingClientRect()的返回值是一个DOMRect对象
    this.rect = (this.$el as HTMLDivElement).getBoundingClientRect();
    this.gl = (this.$refs.myGLCanvas as HTMLCanvasElement).getContext('webgl') as WebGLRenderingContext;
    this.setupShaders();
    this.setupBuffers();
    this.gl.clearColor(0, 0, 0, 1); // 用于设置清空颜色缓冲时的颜色值
    this.draw();
  }
}
</script>

<style lang="postcss" scoped>
.domApiPrc{
    /* 为什么不加定位 就不会在页面显示 */
    touch-action: none;
    position: absolute;
    left: 0;top: 0;
    width: 100%;
    height: 100%;
    background-color: grey;
}
</style>
